use cgmath::num_traits::ToPrimitive;
/// 三个 bool 变量 换为 Mode 的一种 简化代码
/// 支持 equal 表达式？
use crossterm::{
    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyModifiers},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{
    collections::{HashMap, HashSet},
    error::Error,
    fmt::Display,
    io::{self, stdin},
};
use tui::{
    backend::{Backend, CrosstermBackend},
    layout::{Constraint, Direction, Layout, Rect},
    style::{Color, Modifier, Style},
    text::{Span, Spans, Text},
    widgets::{Block, Borders, Clear, List, ListItem, Paragraph},
    Frame, Terminal,
};
use unicode_width::UnicodeWidthStr;

use crate::evaluator::Evaluator;
use crate::expr::Expr;
use crate::parser::Parser;
use crate::tokstr::TokStr;
use crate::utils::triangle_normal;
use crate::vul::vul_render;
use crate::vul::Normal;
use crate::vul::Vertex;
use core::ops::Range;
enum InputMode {
    Normal,
    Editing,
    SetRange,
    SelectFunc,
    // Help,
}
#[derive(PartialEq)]
enum EditItem {
    ZEqual,
    XEqual,
    YEqual,
    RhoEqual,
    ValRange(String),
}
impl Display for EditItem {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &&self {
            Self::ZEqual => write!(f, "z"),
            Self::XEqual => write!(f, "x"),
            Self::YEqual => write!(f, "y"),
            Self::RhoEqual => write!(f, "Rho"),
            Self::ValRange(v) => write!(f, "{v}"),
        }
    }
}

#[derive(PartialEq)]
enum Coordinate {
    Rectangular,
    Parametric,
    Polar,
}
impl Display for Coordinate {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Rectangular => write!(f, "Rectangular Coordinate"),
            Self::Polar => write!(f, "Polar Coordinate"),
            Self::Parametric => write!(f, "Parametric Coordinate"),
        }
    }
}

/// App holds the state of the application
struct App {
    // show_func_tips: bool,
    show_help: bool,
    show_range_tips: bool,
    /// Current value of the input box
    input: String,
    filter_index: usize,
    filter_words: String,
    filtered: Vec<String>,
    /// current input item, range or equation or parameter function
    item: EditItem,
    // Coordinate type
    coordinate: Coordinate,
    /// current equations
    equations: HashMap<String, Expr>,
    /// many val ranges
    val_ranges: HashMap<String, Range<f32>>,
    /// Current input mode
    input_mode: InputMode,
    /// History of recorded messages
    messages: Vec<String>,
}
impl App {
    fn update_filter(&mut self) {
        self.filtered = self
            .val_ranges
            .iter()
            .filter(|(k, _)| {
                k.len() == 0 || self.filter_words.split_whitespace().all(|w| k.contains(w))
            })
            .map(|(k, _)| k.clone())
            .collect();
        self.filtered.sort();
        self.filtered.dedup();
        self.filter_index = 0;
    }
    fn state_key(&mut self, i: char) {
        match i {
            '0' => {
                self.coordinate = Coordinate::Rectangular;
                self.item = EditItem::ZEqual;
            }
            '1' => {
                self.coordinate = Coordinate::Parametric;
                self.item = EditItem::ZEqual;
            }
            '2' => {
                self.coordinate = Coordinate::Polar;
                self.item = EditItem::RhoEqual;
            }
            _ => (),
        }
    }
}

impl Default for App {
    fn default() -> App {
        let names = vec!["x", "y", "z", "theta", "psi"];
        let mut ranges = HashMap::new();
        names.iter().for_each(|n| {
            ranges.insert(n.to_string(), -3.0..3.0);
        });
        let names = names.iter().map(|n| n.to_string()).collect();
        App {
            show_help: false,
            show_range_tips: false,
            // show_func_tips: false,
            filter_index: 0,
            filter_words: String::new(),
            filtered: names,
            coordinate: Coordinate::Rectangular,
            input: String::new(),
            item: EditItem::ZEqual,
            equations: HashMap::new(),
            val_ranges: ranges,
            input_mode: InputMode::Normal,
            messages: Vec::new(),
        }
    }
}

pub fn launch() -> Result<(), Box<dyn Error>> {
    // setup terminal
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // create app and run it
    let app = App::default();
    let res = run_app(&mut terminal, app);
    // restore terminal
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        println!("{:?}", err)
    }

    Ok(())
}

const FUNC_LIST: [&str; 10] = [
    "log", "sin", "cos", "tan", "arcsin", "arccos", "arctan", "sec", "csc", "cot",
];

fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
    loop {
        terminal.draw(|f| ui(f, &app))?;
        // 事件循环
        if let Event::Key(key) = event::read()? {
            match app.input_mode {
                InputMode::SetRange => match key.code {
                    // 选取变量用于设置范围
                    KeyCode::Char(c) => {
                        // 输入字符 每次输入 自动过滤
                        app.filter_words.push(c);
                        app.update_filter();
                    }
                    KeyCode::Backspace => {
                        // 删除字符 自动过滤
                        app.filter_words.pop();
                        app.update_filter();
                    }
                    KeyCode::Tab => {
                        app.filter_index = (app.filter_index + 1) % app.filtered.len();
                    }
                    KeyCode::Enter => {
                        // 选择当前第一个
                        app.input_mode = InputMode::Editing;
                        app.item = EditItem::ValRange(app.filtered[app.filter_index].clone());
                        app.show_range_tips = false;
                    }
                    KeyCode::Esc => {
                        // 退出选择
                        app.input_mode = InputMode::Normal;
                        app.show_help = false;
                        app.show_range_tips = false;
                    }
                    _ => (),
                },

                InputMode::SelectFunc => match key.code {
                    // 选择用于补全的函数
                    KeyCode::Char('h') => {
                        // 帮助
                        app.show_help = !app.show_help;
                    }
                    KeyCode::Char(x) if x.is_ascii_digit() => {
                        // 常用函数提示
                        let i = x.to_digit(10).unwrap_or(0) as usize;
                        app.input.push_str(FUNC_LIST[i]);
                        app.input.push('(');
                        app.input_mode = InputMode::Editing;
                    }
                    KeyCode::Esc => {
                        // 退出
                        app.input_mode = InputMode::Normal;
                        app.show_help = false;
                        app.show_range_tips = false;
                    }
                    _ => (),
                },
                InputMode::Normal => match key.code {
                    // 常规模式
                    KeyCode::Char('h') => {
                        app.show_help = !app.show_help;
                    }
                    KeyCode::Char(d) if d.is_numeric() => app.state_key(d),
                    KeyCode::Char('x') if Coordinate::Parametric == app.coordinate => {
                        app.item = EditItem::XEqual
                    }
                    KeyCode::Char('y') if Coordinate::Parametric == app.coordinate => {
                        app.item = EditItem::YEqual
                    }
                    KeyCode::Char('z') if Coordinate::Parametric == app.coordinate => {
                        app.item = EditItem::ZEqual
                    }
                    KeyCode::Char('d') if Coordinate::Rectangular == app.coordinate => {
                        let mut set = HashSet::new();
                        let e = app
                            .equations
                            .get(&EditItem::ZEqual.to_string())
                            .unwrap()
                            .clone();
                        e.count_vals(&mut set);
                        let dev_e = set
                            .iter()
                            .map(|var| -> String {
                                format!(
                                    "{}d{}",
                                    Evaluator::derivative(e.clone(), &var.to_string()),
                                    var.to_string()
                                )
                            })
                            .collect::<Vec<String>>()
                            .join("+");
                        app.messages.push(format!("Deriv z'={}", dev_e.to_string()));
                        app.equations.insert(EditItem::ZEqual.to_string(), e);
                    }
                    KeyCode::Char('r') => match app.coordinate {
                        Coordinate::Parametric => {
                            let mut tmp_e: Vec<(&String, &Expr)> = app
                                .equations
                                .iter()
                                .filter_map(|e| {
                                    if e.0.eq("x") || e.0.eq("y") || e.0.eq("z") {
                                        Some(e)
                                    } else {
                                        None
                                    }
                                })
                                .collect();
                            tmp_e.sort_by_key(|e| e.0);
                            render_one_para_function(
                                tmp_e.iter().map(|e| e.1.clone()).collect(),
                                app.val_ranges
                                    .get(&'t'.to_string())
                                    .unwrap_or(&(-3.0..3.0))
                                    .clone(),
                                0.01,
                            )
                        }
                        Coordinate::Rectangular => render_two_para_func(
                            app.equations
                                .get(&EditItem::ZEqual.to_string())
                                .unwrap()
                                .to_owned(),
                            app.val_ranges.clone(),
                        ),
                        Coordinate::Polar => render_polar_function(
                            app.equations.get(&EditItem::RhoEqual.to_string()).unwrap(),
                            app.val_ranges.clone(),
                            0.01,
                        ),
                    },
                    KeyCode::Char('v') => {
                        app.show_range_tips = true;
                        app.input_mode = InputMode::SetRange;
                    }
                    KeyCode::Char('i') => {
                        app.input_mode = InputMode::Editing;
                    }
                    KeyCode::Char('q') => {
                        return Ok(());
                    }
                    KeyCode::Esc => {
                        app.input_mode = InputMode::Normal;
                        app.show_help = false;
                        app.show_range_tips = false;
                    }
                    _ => {}
                },
                InputMode::Editing => {
                    match key.code {
                        KeyCode::Tab => {
                            let mut count = 0;
                            app.input
                                .chars()
                                .map(|c| match c {
                                    '(' => count += 1,
                                    ')' => count -= 1,
                                    _ => (),
                                })
                                .last();
                            app.input.push_str(")".repeat(count).as_str());
                        }
                        KeyCode::Enter => match app.item {
                            EditItem::ZEqual
                            | EditItem::XEqual
                            | EditItem::YEqual
                            | EditItem::RhoEqual => {
                                let equation = read_equation(app.input.clone());
                                let mut set = HashSet::new();
                                equation.count_vals(&mut set);
                                app.val_ranges
                                    .extend(set.iter().map(|s| (s.to_owned(), -3.0..3.0))); // 添加默认参数范围
                                app.filtered
                                    .push(set.iter().map(|s| s.to_owned()).collect());
                                app.messages.push(format!("{}={equation}", &app.item));
                                app.equations.insert(app.item.to_string(), equation.clone());
                                match app.coordinate {
                                    Coordinate::Rectangular => {
                                        render_two_para_func(equation, app.val_ranges.clone())
                                    }
                                    Coordinate::Polar => render_polar_function(
                                        app.equations.get(&EditItem::RhoEqual.to_string()).unwrap(),
                                        app.val_ranges.clone(),
                                        0.01,
                                    ),
                                    _ => app.input_mode = InputMode::Normal,
                                }
                            }
                            EditItem::ValRange(ref valr) => {
                                let res: String = app.input.drain(..).collect();
                                let res: Vec<f32> = res
                                    .split_whitespace()
                                    .filter_map(|v| v.parse::<f32>().ok())
                                    .collect();
                                if res.len() != 2 {
                                    panic!("range 格式不正确");
                                }
                                app.val_ranges.insert(valr.clone(), res[0]..res[1]);
                                app.messages.push(format!(
                                    "val {} range {} .. {}",
                                    app.item, res[0], res[1]
                                ));
                            }
                        },
                        KeyCode::Char(c) => {
                            if key.modifiers == KeyModifiers::ALT {
                                match c {
                                    'f' => app.input_mode = InputMode::SelectFunc,
                                    _ => (),
                                }
                            } else if key.modifiers == KeyModifiers::CONTROL {
                                match c {
                                    'c' => app.input.clear(),
                                    _ => (),
                                }
                            } else {
                                app.input.push(c);
                            }
                        }
                        KeyCode::Backspace => {
                            app.input.pop();
                        }
                        KeyCode::Esc => {
                            app.input_mode = InputMode::Normal;
                            app.show_help = false;
                            app.show_range_tips = false;
                        }
                        _ => {}
                    }
                }
            }
        }
    }
}

fn ui<B: Backend>(f: &mut Frame<B>, app: &App) {
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .margin(2)
        .constraints(
            [
                Constraint::Length(1),
                Constraint::Length(3),
                Constraint::Min(1),
            ]
            .as_ref(),
        )
        .split(f.size());

    let (msg, style) = match app.input_mode {
        InputMode::Normal | InputMode::SetRange | InputMode::SelectFunc => (
            vec![
                Span::raw("Press "),
                Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" to exit; "),
                Span::styled("i", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for editing; "),
                Span::styled("x / y / z", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for variable; "),
                Span::styled("v", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for select range; "),
                Span::styled("r", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for render; "),
                Span::styled("d", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for derivative; "),
                Span::styled("h", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for help."),
            ],
            Style::default().add_modifier(Modifier::RAPID_BLINK),
        ),
        InputMode::Editing => (
            vec![
                Span::raw("Press "),
                Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" to stop editing, "),
                Span::styled("alt+f", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" for function input tips; "),
                Span::styled("ctrl+c", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" to clean input area; "),
                Span::styled("Tab", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" to complete parentheses; "),
                Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)),
                Span::raw(" to finish."),
            ],
            Style::default(),
        ),
    };
    let mut text = Text::from(Spans::from(msg));
    text.patch_style(style);
    let help_message = Paragraph::new(text);
    f.render_widget(help_message, chunks[0]);

    let input = Paragraph::new(app.input.as_ref())
        .style(match app.input_mode {
            InputMode::Normal | InputMode::SetRange => Style::default(),
            InputMode::Editing | InputMode::SelectFunc => Style::default().fg(Color::Yellow),
        })
        .block(Block::default().borders(Borders::ALL).title(
            if let EditItem::ValRange(c) = &app.item {
                format!("Range for {}", c)
            } else {
                format!("Equation {} = ", app.item)
            },
        ));
    f.render_widget(input, chunks[1]);
    match app.input_mode {
        InputMode::Normal | InputMode::SetRange =>
            // Hide the cursor. `Frame` does this by default, so we don't need to do anything here
            {}

        InputMode::Editing | InputMode::SelectFunc => {
            // Make the cursor visible and ask tui-rs to put it at the specified coordinates after rendering
            f.set_cursor(
                // Put cursor past the end of the input text
                chunks[1].x + app.input.width() as u16 + 1,
                // Move one line down, from the border to the input line
                chunks[1].y + 1,
            )
        }
    }
    // 下方分左右
    let bot = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
        .split(chunks[2]);
    // 下方左侧 message
    let messages: Vec<ListItem> = app
        .messages
        .iter()
        .enumerate()
        .map(|(i, m)| {
            let content = vec![Spans::from(Span::raw(format!("{}: {}", i, m)))];
            ListItem::new(content)
        })
        .collect();
    let messages =
        List::new(messages).block(Block::default().borders(Borders::ALL).title("Messages"));
    f.render_widget(messages, bot[0]);
    // 下方右侧 state
    let mut state_tips: Vec<ListItem> = Vec::new();
    let state_info = vec![
        Coordinate::Rectangular.to_string(),
        Coordinate::Parametric.to_string(),
        Coordinate::Polar.to_string(),
    ];
    // 组装
    let mut coordinate_info: Vec<ListItem> = state_info
        .iter()
        .enumerate()
        .map(|(i, c)| {
            let content = vec![
                Span::styled(
                    format!("{i} "),
                    Style::default().add_modifier(Modifier::BOLD),
                ),
                Span::raw(format!(
                    "{}{}",
                    c,
                    if app.coordinate.to_string().eq(c) {
                        " ⮐"
                    } else {
                        ""
                    }
                )),
            ];
            ListItem::new(Spans::from(content))
        })
        .collect();
    let mut equation_info: Vec<ListItem> = app
        .equations
        .iter()
        .map(|e| {
            ListItem::new(Spans::from(Vec::from([Span::raw(format!(
                "{}={}",
                e.0, e.1
            ))])))
        })
        .collect();
    state_tips.append(&mut coordinate_info);
    state_tips.append(&mut equation_info);
    let state_block =
        List::new(state_tips).block(Block::default().borders(Borders::ALL).title("States"));
    f.render_widget(state_block, bot[1]); //this clears out the background

    // 选择变量 设定范围
    if app.show_range_tips {
        // 单行消息 输入框 展示框
        let size = f.size();
        let area = centered_rect(60, 80, size);
        let chunks = Layout::default()
            .direction(Direction::Vertical)
            .margin(2)
            .constraints(
                [
                    Constraint::Length(1),
                    Constraint::Length(3),
                    Constraint::Min(1),
                ]
                .as_ref(),
            )
            .split(area);
        // 使用提示
        let tips = vec![
            Span::raw("Key words seperated by whitespace to search"),
            Span::styled("Press Tab", Style::default().add_modifier(Modifier::BOLD)),
            Span::raw(" to change the hilight one; "),
            Span::styled("Press Enter", Style::default().add_modifier(Modifier::BOLD)),
            Span::raw(" to select the highlight one."),
        ];
        let mut text = Text::from(Spans::from(tips));
        text.patch_style(Style::default());
        let help_message = Paragraph::new(text);
        // 输入框
        let filter_bank = Paragraph::new(app.filter_words.as_ref())
            .style(Style::default().fg(Color::Yellow))
            .block(Block::default().borders(Borders::ALL).title("filter"));
        // 显示框 取过滤过的 符合条件的备选
        let val_ranges: Vec<ListItem> = app
            .filtered
            .iter()
            .enumerate()
            .map(|(i, k)| {
                let v = app.val_ranges.get(k).unwrap();
                let content = vec![
                    Span::styled(k.to_string(), Style::default().add_modifier(Modifier::BOLD)),
                    Span::raw(format!(" {} .. {}", v.start, v.end)),
                ];
                if i == app.filter_index {
                    ListItem::new(Spans::from(content))
                        .style(Style::default().bg(Color::White).fg(Color::Black))
                } else {
                    ListItem::new(Spans::from(content))
                }
            })
            .collect();
        let candidates =
            List::new(val_ranges).block(Block::default().borders(Borders::ALL).title("variables"));
        // 一起绘制
        f.render_widget(Clear, area); // 清空区域
        f.render_widget(help_message, chunks[0]);
        f.render_widget(filter_bank, chunks[1]);
        f.render_widget(candidates, chunks[2]);
    }
    // 选择函数 自动补全
    if let InputMode::SelectFunc = app.input_mode {
        // 划分区域
        let size = f.size();
        let area = centered_rect(60, 80, size);
        // 准备内容
        let func_tips: Vec<ListItem> = FUNC_LIST
            .iter()
            .enumerate()
            .map(|(i, m)| {
                let content = vec![
                    Span::styled(
                        i.to_string() + " ",
                        Style::default().add_modifier(Modifier::BOLD),
                    ),
                    Span::raw(*m),
                ];
                ListItem::new(Spans::from(content))
            })
            .collect();
        // 构造方框
        let help_block =
            List::new(func_tips).block(Block::default().borders(Borders::ALL).title("Help"));
        f.render_widget(Clear, area); // 清空
        f.render_widget(help_block, area); // 绘制
    };
    // 弹窗帮助
    if app.show_help {
        // 划分区域
        let size = f.size();
        let area = centered_rect(60, 80, size);
        // 准备内容
        let help_info = vec![
            ("built-in constants", " e, pi "),
            ("Global", "---:"),
            ("Esc", " Return Normal Mode"),
            ("q", " quit the current window frame"),
            ("\nNormal Mode", "---:"),
            ("h", " help popup on/off"),
            ("r", " render the function"),
            ("d", " derivation"),
            ("i", " Enter `Editing Mode`: edit equation"),
            ("x / y / z", " choose the variable to note a equation"),
            (
                "v",
                " Enter `Val-Range Mode`: edit variable range, just 2 numbers in a line, with space between them",
            ),
            ("\nEditing Mode", "---:"),
            ("Alt+f", " function input tips"),
            ("Ctrl+c", " clear inputs"),
            ("Tab", " complete the parentheses"),
            ("Enter", " finish editing. If contains 2 variables, render immediately"),
            ("\n Vulkan Mode", "---:"),
            ("v", " swap the viwer position, initial or along the x/y/z axis."),
        ];
        // 组装
        let help_info: Vec<ListItem> = help_info
            .iter()
            .map(|(i, m)| {
                let content = vec![
                    Span::styled(*i, Style::default().add_modifier(Modifier::BOLD)),
                    Span::raw(*m),
                ];
                ListItem::new(Spans::from(content))
            })
            .collect();
        let help_block =
            List::new(help_info).block(Block::default().borders(Borders::ALL).title("Help"));
        // 渲染
        f.render_widget(Clear, area); // 清空
        f.render_widget(help_block, area); // 绘制
    }
}

/// 划出弹窗范围
fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
    // 竖划两刀左右 取用中间
    let popup_layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints(
            [
                Constraint::Percentage((100 - percent_y) / 2),
                Constraint::Percentage(percent_y),
                Constraint::Percentage((100 - percent_y) / 2),
            ]
            .as_ref(),
        )
        .split(r);
    // 横划两刀上下 留用中间
    Layout::default()
        .direction(Direction::Horizontal)
        .constraints(
            [
                Constraint::Percentage((100 - percent_x) / 2),
                Constraint::Percentage(percent_x),
                Constraint::Percentage((100 - percent_x) / 2),
            ]
            .as_ref(),
        )
        .split(popup_layout[1])[1]
}

/// 从给定字符串读取抽象语法树AST
pub fn read_equation(s: String) -> Expr {
    let t = TokStr::new(s);
    let mut p = Parser::new(t);
    p.parse_expr().expect("parse expression failed")
}

pub fn read_x_range() -> Range<f32> {
    -3.0..3.0
}

pub fn read_y_range() -> Range<f32> {
    -3.0..3.0
}

pub fn touch_var_demo() {
    let mut s = String::new();
    stdin().read_line(&mut s).unwrap();
    let equation = read_equation(s);
    let mut set = HashSet::new();
    let mut app = App::default();
    equation.count_vals(&mut set);
    app.val_ranges
        .extend(set.iter().map(|s| (s.to_owned(), -3.0..3.0))); // 添加默认参数范围
    app.messages.push(format!("{}={equation}", &app.item));
    app.equations.insert(app.item.to_string(), equation.clone());
    println!(
        "equations: {:#?}\nval_ranges: {:#?}\nval set: {:#?}",
        app.equations, app.val_ranges, set
    );
}
pub fn test_demo() {
    let mut s = String::new();
    stdin().read_line(&mut s).unwrap();
    let t = TokStr::new(s);
    println!("tokstr {:?}", t.collect::<Vec<Expr>>());
}
pub fn render_two_para_func(e: Expr, syms: HashMap<String, Range<f32>>) {
    let mut set = HashSet::new();
    e.count_vals(&mut set);
    let mut local_vertex = vec![Vertex::zero()];
    let mut local_normal = vec![Normal::zero()];
    let mut local_index: Vec<u32> = vec![];
    let mut vals = set.iter();
    let x_range = syms
        .get(vals.next().unwrap_or(&"x".to_string()))
        .unwrap_or(&(-3.0..3.0));
    let y_range = syms
        .get(vals.next().unwrap_or(&"y".to_string()))
        .unwrap_or(&(-3.0..3.0));
    expand_function(
        e,
        x_range.clone(),
        y_range.clone(),
        0.1,
        &mut local_index,
        &mut local_vertex,
        &mut local_normal,
    );
    expand_xy_plain(
        x_range.start.floor() as isize..x_range.end.ceil() as isize,
        y_range.start.floor() as isize..y_range.end.ceil() as isize,
        &mut local_index,
        &mut local_vertex,
        &mut local_normal,
    );

    vul_render(&local_index, &local_normal, &local_vertex);
}
pub fn render_polar_function(
    // rho as func name
    rho: &Expr,
    val_ranges: HashMap<String, Range<f32>>,
    dense: f32,
) {
    let mut set = HashSet::new();
    rho.count_vals(&mut set);
    let default_names = ["theta".to_string(), "psi".to_string()];
    let mut val_names = set.iter();
    let theta_name = val_names.next().unwrap_or(&default_names[0]);
    let psi_name = val_names.next().unwrap_or(&default_names[1]);
    let theta_range = val_ranges.get(theta_name).unwrap_or(&(-3.0..3.0));
    let psi_range = val_ranges.get(psi_name).unwrap_or(&(-3.0..3.0));
    let mut points = vec![];
    let mut environment = HashMap::new();
    for theta_count in 0..(((theta_range.end - theta_range.start) / dense).trunc() as usize) {
        let theta = theta_range.start + theta_count as f32 * dense;
        for psi_count in 0..(((psi_range.end - psi_range.start) / dense).trunc() as usize) {
            let psi = psi_range.start + psi_count as f32 * dense;
            environment.insert(theta_name.to_string(), Expr::Cstf(theta));
            environment.insert(psi_name.to_string(), Expr::Cstf(psi));
            let rho_value = Evaluator::eval_expr(rho, &environment);
            points.push(vec![
                rho_value * theta.cos(),
                rho_value * theta.sin(),
                rho_value * psi.sin(),
            ]);
        }
    }
    let mut local_vertex = vec![];
    let mut local_normal = vec![];
    let mut local_index: Vec<u32> = vec![];
    let (x_max, y_max) = find_xy_max(points.to_owned());
    expand_xy_plain(
        -x_max.floor().to_isize().unwrap_or(-3)..x_max.ceil().to_isize().unwrap_or(3),
        -y_max.floor().to_isize().unwrap_or(-3)..y_max.ceil().to_isize().unwrap_or(3),
        &mut local_index,
        &mut local_vertex,
        &mut local_normal,
    );
    scatter(
        points,
        &mut local_index,
        &mut local_vertex,
        &mut local_normal,
    );
    vul_render(&local_index, &local_normal, &local_vertex);
}
fn find_xy_max(points: Vec<Vec<f32>>) -> (f32, f32) {
    let x_max = points
        .iter()
        .map(|p| p[0].abs())
        .max_by(|x1, x2| x1.partial_cmp(&x2).unwrap_or(std::cmp::Ordering::Equal))
        .unwrap_or(3.0);
    let y_max = points
        .iter()
        .map(|p| p[1].abs())
        .max_by(|y1, y2| y1.partial_cmp(&y2).unwrap_or(std::cmp::Ordering::Equal))
        .unwrap_or(3.0);
    (x_max, y_max)
}
// 如何防止接口面过大的问题？ TODO 整理一下 Default 写成 config 类
fn render_one_para_function(exprs: Vec<Expr>, t_range: Range<f32>, dense: f32) {
    let mut set = HashSet::new();
    exprs.iter().for_each(|e| {
        e.count_vals(&mut set);
    });
    if exprs.len() != 3 || set.len() != 1 {
        panic!("parametric function should comprise of 3 equations and 1 parameter")
    } else {
        let para_name: String = set.iter().next().unwrap().to_owned();
        let mut points: Vec<Vec<f32>> = Vec::new();
        let mut t_dict = HashMap::new();
        for t_count in 0..(((t_range.end - t_range.start) / dense).trunc() as usize) {
            t_dict.insert(
                para_name.clone(),
                Expr::Cstf(t_range.start + t_count as f32 * dense),
            );
            points.push(
                exprs
                    .iter()
                    .map(|e| Evaluator::eval_expr(&e, &t_dict) as f32)
                    .collect(),
            );
        }
        let mut local_vertex = vec![Vertex::zero()];
        let mut local_normal = vec![Normal::zero()];
        let mut local_index: Vec<u32> = vec![];
        let (x_max, y_max) = find_xy_max(points.to_owned());
        expand_xy_plain(
            -x_max.floor().to_isize().unwrap_or(-3)..x_max.ceil().to_isize().unwrap_or(3),
            -y_max.floor().to_isize().unwrap_or(-3)..y_max.ceil().to_isize().unwrap_or(3),
            &mut local_index,
            &mut local_vertex,
            &mut local_normal,
        );
        scatter(
            points,
            &mut local_index,
            &mut local_vertex,
            &mut local_normal,
        );
        vul_render(&local_index, &local_normal, &local_vertex);
    }
}

fn scatter(
    points: Vec<Vec<f32>>,
    local_index: &mut Vec<u32>,
    local_vertex: &mut Vec<Vertex>,
    local_normal: &mut Vec<Normal>,
) {
    points.iter().for_each(|p| {
        let i = vec![1, 2, 3, 3, 4, 1u32];
        let mut v = expand_point_to_triangle(p.to_owned(), [1.0, 0.0, 0.0, 1.0], 0.1);
        let mut n = triangle_normal(&local_vertex[0], &local_vertex[1], &local_vertex[2]);

        local_index.append(
            &mut i
                .iter()
                .map(|x| x + local_vertex.len() as u32 - 1)
                // .inspect(|_| println!("{}", local_vertex.len()))
                .collect(),
        );
        local_vertex.append(&mut v);
        local_normal.append(&mut n);
    });
}

fn expand_point_to_triangle(point: Vec<f32>, color: [f32; 4], epsilon: f32) -> Vec<Vertex> {
    if point.len() != 3 {
        panic!("point have just 3 number")
    }
    // TODO color
    vec![
        Vertex {
            position: [point[0], point[1], point[2]],
            color,
        },
        Vertex {
            position: [point[0] + epsilon, point[1], point[2]],
            color,
        },
        Vertex {
            position: [point[0], point[1] + epsilon, point[2]],
            color,
        },
    ]
}
// range right open interval
fn expand_function(
    func: Expr,
    x_range: Range<f32>,
    y_range: Range<f32>,
    dense: f32,
    local_index: &mut Vec<u32>,
    local_vertex: &mut Vec<Vertex>,
    local_normal: &mut Vec<Normal>,
) {
    let z_dict = Evaluator::eval_range(&func, x_range.clone(), y_range.clone(), dense);
    let z_max = z_dict
        .values()
        .max_by(|&x, &y| x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal))
        .unwrap();
    let z_min = z_dict
        .values()
        .min_by(|&x, &y| x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal)) // NOTE NaN 与 Partial Order
        .unwrap();
    let z_step = z_max - z_min;
    for x_count in 0..(((x_range.end - x_range.start) / dense).trunc() as usize) {
        let x = x_range.start + x_count as f32 * dense;
        for y_count in 0..(((y_range.end - y_range.start) / dense).trunc() as usize) {
            let y = y_range.start + y_count as f32 * dense;
            let a = (x, y, z_dict[&(x_count, y_count)]);
            let b = (x + dense, y, z_dict[&(x_count + 1, y_count)]);
            let c = (x + dense, y + dense, z_dict[&(x_count + 1, y_count + 1)]);
            let d = (x, y + dense, z_dict[&(x_count, y_count + 1)]);
            // let colorz = z_dict[&(x_count, y_count)];

            let (mut v, mut n, i) = construct_square(
                a,
                b,
                c,
                d,
                [
                    0.0 + (1.0 / z_step) * (z_dict[&(x_count, y_count)] - z_min),
                    0.0,
                    1.0 - (1.0 / z_step) * (z_dict[&(x_count, y_count)] - z_min),
                    1.0,
                ],
            );

            local_index.append(
                &mut i
                    .iter()
                    .map(|x| x + local_vertex.len() as u32 - 1)
                    .collect(),
            );
            local_vertex.append(&mut v);
            local_normal.append(&mut n);
        }
    }
}
fn expand_xy_plain(
    x_range: Range<isize>,
    y_range: Range<isize>,
    local_index: &mut Vec<u32>,
    local_vertex: &mut Vec<Vertex>,
    local_normal: &mut Vec<Normal>,
) {
    for i in x_range {
        for j in y_range.clone() {
            let (mut v, mut n, i) = construct_square(
                (i as f32, j as f32, 0.0),
                (i as f32 + 1.0, j as f32, 0.0),
                (i as f32 + 1.0, j as f32 + 1.0, 0.0),
                (i as f32, j as f32 + 1.0, 0.0),
                [
                    ((i + j + 1).abs() % 2) as f32,
                    ((i + j + 1).abs() % 2) as f32,
                    ((i + j + 1).abs() % 2) as f32,
                    // 1.0, 1.0, 1.0, 1.0,
                    1.0,
                ],
            );
            local_index.append(
                &mut i
                    .iter()
                    .map(|x| x + local_vertex.len() as u32 - 1)
                    .collect(),
            );
            local_vertex.append(&mut v);
            local_normal.append(&mut n);
        }
    }
}
// counter clock-wise 4 point. from lower left.
fn construct_square(
    a: (f32, f32, f32),
    b: (f32, f32, f32),
    c: (f32, f32, f32),
    d: (f32, f32, f32),
    color: [f32; 4],
) -> (Vec<Vertex>, Vec<Normal>, Vec<u32>) {
    // give a clockwise order vertex
    let vertex = vec![a, b, c, d];
    let local_vertex: Vec<Vertex> = vertex
        .iter()
        .filter_map(|(x, y, z)| {
            Some(Vertex {
                position: [*x, *y, *z],
                color,
            })
        })
        .collect();
    let mut local_normal = triangle_normal(&local_vertex[0], &local_vertex[1], &local_vertex[2]);
    local_normal.append(&mut triangle_normal(
        &local_vertex[1],
        &local_vertex[2],
        &local_vertex[3],
    ));
    let local_index = vec![1, 2, 3, 3, 4, 1u32];
    (local_vertex, local_normal, local_index)
}

pub fn cross_mul(lhs: Normal, rhs: Normal) -> Normal {
    let [a0, a1, a2] = lhs.normal;
    let [b0, b1, b2] = rhs.normal;
    Normal {
        normal: [a1 * b2 - a2 * b1, a2 * b0 - a0 * b2, a0 * b1 - a1 * b0],
    }
}
pub fn test_polar() {
    let e = read_equation("1-sin(theta)".to_string());
    let mut env = HashMap::new();
    env.insert("theta".to_string(), -3.0..3.0);
    render_polar_function(&e, env, 0.1);
}
